package com.bzkj.document.service.purchase.impl;


import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.bzkj.common.constant.BillStatusConstant;
import com.bzkj.common.core.domain.AjaxResult;
import com.bzkj.common.core.domain.model.LoginUser;
import com.bzkj.common.core.page.TableDataInfo;
import com.bzkj.common.domain.NccApiResponse;
import com.bzkj.common.domain.NccRequestDTO;
import com.bzkj.common.enums.DocumentType;
import com.bzkj.common.utils.DataProcessCommonUtils;
import com.bzkj.common.utils.MessageUtil;
import com.bzkj.common.utils.http.NccHttpUtils;
import com.bzkj.document.domain.purchaseinorder.vo.PurchaseInboundBodyVO;
import com.bzkj.document.domain.purchaseinorder.vo.PurchaseInboundHeadVO;
import com.bzkj.document.enums.InventoryCheck;
import com.bzkj.document.exception.InventoryException;
import com.bzkj.document.mapper.PurchaseInStockMapper;
import com.bzkj.document.mapper.WmsWareHouseInventoryMapper;
import com.bzkj.document.service.purchase.PurchaseService;
import com.bzkj.document.utils.common.DataProcessUtils;
import com.bzkj.document.utils.common.DocumentNoUtils;
import com.bzkj.document.utils.common.InventoryManagerUtils;
import com.bzkj.document.utils.purchaseorder.PurchaseOrderUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;


/**
 * @projectName: bzkj-wms
 * @package: com.bzkj.document.service.purchase.impl
 * @className: PurchaseServiceImpl
 * @description: 采购入库单服务层
 * @author: C1309
 * @createDate: 2024年11月18日
 * @version: v1.0
 */
@Service
public class PurchaseServiceImpl implements PurchaseService {

    /**
     * 查询NCC采购订单
     */
    private static final String PURCHASE_ORDER_URL = "/nccloud/api/pu/order/querybyscheme";

    /**
     * NCC创建采购入库单
     */
    private static final String PURCHASE_IN_ADD_URL = "/nccloud/api/ic/purchasein/save";

    /**
     * NCC更新采购入库单
     */
    private static final String PURCHASE_UPDATE_URL = "/nccloud/api/ic/purchasein/update";

    /**
     * NCC接口请求工具
     */
    @Resource
    private NccHttpUtils nccHttpUtils;

    /**
     * 采购入库持久层
     */
    @Resource
    private PurchaseInStockMapper purchaseInStockMapper;

    @Resource
    private WmsWareHouseInventoryMapper wareHouseInventoryMapper;

    @Resource
    private InventoryManagerUtils inventoryManagerUtils;

    /**
     * WMS单据号生成
     */
    @Resource
    private DocumentNoUtils documentNoUtils;

    /**
     * 采购订单、采购入库单工具类
     */
    @Resource
    private PurchaseOrderUtils purchaseOrderUtils;

    /**
     * 消息提示工具类
     */
    @Resource
    private MessageUtil messageUtil;

    /**
     * 固定的 pk_org
     */
    private static final String PK_ORG = "111";


    /**
     * 查询NCC采购订单
     *
     * @param purchaseOrderRequestDTO 查询条件
     * @return 查询结果
     */
    @Override
    public TableDataInfo selectPurchaseOrder(NccRequestDTO purchaseOrderRequestDTO) {

        try {
            // 发起请求并处理响应
            NccApiResponse nccApiResponse = nccHttpUtils.post(PURCHASE_ORDER_URL, JSONObject.toJSONString(purchaseOrderRequestDTO));

            // 验证响应状态
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);

            // 解析NCC返回的采购订单数据
            List<Map<String, Object>> dataList = purchaseOrderUtils.processNccPurchaseOrderResponse(nccApiResponse);

//            if (dataList == null || dataList.isEmpty()) {
//                throw new RuntimeException("Oops~ 当前条件下没有找到单据，试试调整查询条件吧！");
//            }

            // 返回分页数据
            return DataProcessUtils.startPageInfo(purchaseOrderRequestDTO.getPageNum(), purchaseOrderRequestDTO.getPageSize(), dataList);
        } catch (Exception e) {
            // 捕获请求异常并返回具体错误提示
            String errorMessage = messageUtil.operateExceptionMessage(DocumentType.PURCHASE_ORDER.getCode(), e, "查询");
            throw new RuntimeException(errorMessage, e);
        }

    }


    /**
     * 将NCC创建的采购入库单插入WMS采购入库单表
     *
     * @return 操作结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult insertPurchase(Map<String, Object> purchaseInboundOrder, LoginUser loginUser) {
        List<String> vbillcodeList = new ArrayList<>();

        try {
            // 将采购入库单数据转换为 JSON 对象
            JSONObject jsonObject = new JSONObject(purchaseInboundOrder);

            // 校验采购入库单数据
            JSONObject purchaseInStock = checkPurchaseInStock(JSONObject.parseObject(jsonObject.toJSONString()));

            // 组织 NCC 请求参数
            JSONObject requestJson = assemblyRequest(purchaseInStock, loginUser.getUsername());

            // 发送 NCC 请求
            NccApiResponse nccApiResponse = nccHttpUtils.post(PURCHASE_IN_ADD_URL, "[" + requestJson.toJSONString() + "]");

            // 校验 NCC 返回数据
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);

            // 解析 NCC 返回数据
            List<Map<String, Object>> dataList = purchaseOrderUtils.processNccInboundOrderResponse(nccApiResponse);

            if (dataList == null || dataList.isEmpty()) {
                throw new RuntimeException("Oops~ 当前条件下没有找到单据，试试调整查询条件吧！");
            }

            // 处理每个入库单
            for (Map<String, Object> inboundOrder : dataList) {
                processInboundOrder(inboundOrder, loginUser, vbillcodeList, (List<Map<String, Object>>) purchaseInboundOrder.get("details"));
            }

        } catch (Exception e) {
            String exceptionMessage = messageUtil.operateExceptionMessage(DocumentType.PURCHASE_INBOUND.getCode(), e, "创建");
            throw new RuntimeException(exceptionMessage, e);
        }

        // 返回成功消息
        return AjaxResult.success(messageUtil.operateSuccessMessage(vbillcodeList, DocumentType.PURCHASE_INBOUND.getCode(), "创建"));
    }

    /**
     * 处理单个采购入库单
     *
     * @param inboundOrder  入库单数据
     * @param loginUser     当前登录用户
     * @param vbillcodeList 入库单编号列表
     */
    @Transactional(rollbackFor = Exception.class)
    public void processInboundOrder(Map<String, Object> inboundOrder, LoginUser loginUser, List<String> vbillcodeList, List<Map<String, Object>> detailsR) {
        @SuppressWarnings("unchecked")
        Map<String, Object> headerMap = (Map<String, Object>) inboundOrder.get("header");

        // 提取并记录入库单编号
        String vbillcode = headerMap.get("vbillcode").toString();
        vbillcodeList.add(vbillcode);

        // 添加额外的头信息
        DataProcessUtils.addHeaderInfo(headerMap, loginUser);

        // 插入表头数据
        int resultCount = purchaseInStockMapper.insertPurchaseInStockHeader(headerMap);
        if (resultCount <= 0) {
            String failureMessage = messageUtil.documentFailureMessage(vbillcodeList, DocumentType.PURCHASE_INBOUND.getCode(), "创建", "表头");
            throw new RuntimeException(failureMessage);
        }

        // 插入表体数据
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> details = (List<Map<String, Object>>) inboundOrder.get("details");
        int detailInsertCount = 0;

        // 表体数据添加额外信息
        DataProcessUtils.addParamsInfo(details, detailsR);

        for (Map<String, Object> detail : details) {
            DataProcessUtils.addDetailInfo(detail, loginUser);
            inventoryManagerUtils.checkBatchNo(details, 1, "warehousein");
            detailInsertCount += purchaseInStockMapper.insertPurchaseInStockDetails(detail);
        }

        // 校验表体数据插入结果
        if (detailInsertCount != details.size()) {
            String failureMessage = messageUtil.documentFailureMessage(vbillcodeList, DocumentType.PURCHASE_INBOUND.getCode(), "创建", "明细");
            throw new RuntimeException(failureMessage);
        }
    }

    /**
     * 修改NCC采购入库单信息
     *
     * @param requestBody 需要修改的采购入库单数据
     * @param loginUser   当前登录用户
     * @param isSign      是否为签字操作
     * @return 修改结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult updatePurchase(Map<String, Object> requestBody, LoginUser loginUser, boolean isSign) {
        try {
            // 提取请求参数
            JSONObject requestBodyObject = new JSONObject(requestBody);
            JSONObject header = requestBodyObject.getJSONObject("header");

            if (header == null) {
                return AjaxResult.warn("小提示：采购入库单据数据异常，请检查！");
            }

            if (header.get("cwarehouseid") != null ){
                header.remove("cwarehouseid");
            }
            String cgeneralhid = header.getString("cgeneralhid");

            Map<String, String> billStateMap = purchaseInStockMapper.getBillStatus(cgeneralhid);
            String billState = billStateMap.get("billState");
            String billCode = billStateMap.get("vbillcode");
            // 校验单据状态（可选）
            if (!isSign) {
                AjaxResult ajaxResult = messageUtil.updateBillMessage(billState, DocumentType.PURCHASE_INBOUND.getDescription());
                if (!ajaxResult.isSuccess()) {
                    return ajaxResult;
                }
                // 处理更新逻辑
                return handleUpdateBills(requestBodyObject, loginUser, billCode);
            }
            // 跳过校验直接处理更新
            return handleUpdateBills(requestBodyObject, loginUser, billCode);
        } catch (Exception e) {
            String exceptionMessage;
            if (!isSign) {
                exceptionMessage = messageUtil.operateExceptionMessage(DocumentType.PURCHASE_INBOUND.getCode(), e, "修改");
            } else {
                exceptionMessage = messageUtil.operateExceptionMessage(DocumentType.PURCHASE_INBOUND.getCode(), e, "签字");
            }
            return AjaxResult.error(exceptionMessage);
        }
    }

    /**
     * 处理已完成的采购入库单
     *
     * @param responseObject 数据
     * @param loginUser      修改人
     * @param billCode       单据编号
     * @return 修改结果
     */
    private AjaxResult handleUpdateBills(JSONObject responseObject, LoginUser loginUser, String billCode) {
        List<String> billCodeList = Collections.singletonList(billCode);
        // 创建数据结构
        Map<String, Object> jsonData = buildJsonData(responseObject);

        try {
            NccApiResponse nccApiResponse = nccHttpUtils.post(PURCHASE_UPDATE_URL, JSONObject.toJSONString(jsonData));
            List<Map<String, Object>> inboundOrderResponseList = purchaseOrderUtils.processNccInboundOrderResponse(nccApiResponse);

            for (Map<String, Object> inboundOrder : inboundOrderResponseList) {
                // 处理单个采购入库单
                processUpdateInboundOrder(inboundOrder, loginUser, billCodeList);
            }

        } catch (Exception e) {
            String errorMessage = messageUtil.operateExceptionMessage(DocumentType.PURCHASE_INBOUND.getCode(), e, "修改");
//            log.error("采购入库单修改异常: ", e);
            throw new RuntimeException(errorMessage, e);
        }
        return AjaxResult.success(messageUtil.operateSuccessMessage(billCodeList, DocumentType.PURCHASE_INBOUND.getCode(), "修改"));
    }

    /**
     * 处理单个修改后的采购入库单
     *
     * @param inboundOrder  修改后的采购入库单数据
     * @param loginUser     当前登录用户
     * @param vbillcodeList 采购入库单编号列表
     */
    private void processUpdateInboundOrder(Map<String, Object> inboundOrder, LoginUser loginUser, List<String> vbillcodeList) {
        @SuppressWarnings("unchecked")
        Map<String, Object> headerMap = (Map<String, Object>) inboundOrder.get("header");

        // 添加额外的头信息
        DataProcessUtils.updateInfo(headerMap, loginUser);

        // 修改表头数据
        int resultCount = purchaseInStockMapper.updateWmsWarehouseInMaterial(headerMap);
        if (resultCount <= 0) {
            String failureMessage = messageUtil.documentFailureMessage(vbillcodeList, DocumentType.PURCHASE_INBOUND.getCode(), "修改", "表头");
            throw new RuntimeException(failureMessage);
        }

        // 修改表体数据
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> details = (List<Map<String, Object>>) inboundOrder.get("details");
        int detailUpdateCount = 0;
        for (Map<String, Object> detail : details) {
            DataProcessUtils.updateInfo(detail, loginUser);
            detailUpdateCount += purchaseInStockMapper.updatePurchaseInStockDetails(detail);
        }
        if (detailUpdateCount != details.size()) {
            String failureMessage = messageUtil.documentFailureMessage(vbillcodeList, DocumentType.PURCHASE_INBOUND.getCode(), "修改", "明细");
            throw new RuntimeException(failureMessage);
        }
    }

    /**
     * 构建采购入库单数据
     *
     * @param responseObject 采购入库单数据
     * @return 构建的采购入库单数据
     */
    private Map<String, Object> buildJsonData(JSONObject responseObject) {
        Map<String, Object> jsonData = new HashMap<>();
        Map<String, String> icPurchaseInH = new HashMap<>();
        List<Map<String, Object>> icPurchaseInB = new ArrayList<>();

        // 构建 "ic_purchasein_h"
        JSONObject header = responseObject.getJSONObject("header");
        if (header != null) {
            String cgeneralhid = header.getString("cgeneralhid");
            icPurchaseInH.put("cgeneralhid", cgeneralhid);
        }

        // 构建 "ic_purchasein_b"
        JSONArray body = responseObject.getJSONArray("details");
        if (body != null && !body.isEmpty()) {
            for (int i = 0; i < body.size(); i++) {
                JSONObject bodyObject = body.getJSONObject(i);
                Map<String, Object> icPurchaseinBodyMap = new HashMap<>();
                icPurchaseinBodyMap.put("cgeneralbid", bodyObject.getString("cgeneralbid"));

                addOptionalField(icPurchaseinBodyMap, bodyObject, "nnum");
                addOptionalField(icPurchaseinBodyMap, bodyObject, "nshouldnum");
                addOptionalField(icPurchaseinBodyMap, bodyObject, "vbatchcode");
                addOptionalField(icPurchaseinBodyMap, bodyObject, "cwarehouseid");

                icPurchaseInB.add(icPurchaseinBodyMap);
            }
        }
        jsonData.put("ic_purchasein_h", icPurchaseInH);
        jsonData.put("ic_purchasein_b", icPurchaseInB);
        return jsonData;
    }

    /**
     * 向Map中添加可选字段
     *
     * @param map        目标Map
     * @param bodyObject JSON数据
     * @param fieldName  字段名
     */
    private void addOptionalField(Map<String, Object> map, JSONObject bodyObject, String fieldName) {
        if (bodyObject.containsKey(fieldName) && bodyObject.getString(fieldName) != null && !bodyObject.getString(fieldName).isEmpty()) {
            map.put(fieldName, bodyObject.getString(fieldName));
        }
    }


    /**
     * WMS采购入库单提交数据校验
     *
     * @param purchaseInBodyVO WMS前端传来的采购入库单参数
     * @return 所需参数
     */
    private JSONObject checkPurchaseInStock(JSONObject purchaseInBodyVO) {
        // 校验阶段，检测是否有必填字段为空
        JSONObject header = purchaseInBodyVO.getJSONObject("header");
        JSONArray details = purchaseInBodyVO.getJSONArray("details");
        // 初始化校验错误信息记录
        StringBuilder errorMessages = new StringBuilder();

        // 校验 header 部分
        checkFieldNotNull(header, "cwarehouseid", "仓库", errorMessages);
        checkFieldNotNull(header, "cemployeeid", "采购员", errorMessages);
        checkFieldNotNull(header, "pk_order", "表头主键", errorMessages);
        checkFieldNotNull(header, "vbillcode", "单据号", errorMessages);
        checkFieldNotNull(header, "ctrantypeid", "单据交易类型", errorMessages);

        // 检查财务结算组织 (cfanaceorgoid) 是否从 details 中取到至少一个
        boolean financeOrgValid = details.stream()
                .map(detail -> ((JSONObject) detail).getJSONObject("pk_psfinanceorg_v"))
                .anyMatch(financeOrg -> financeOrg != null && financeOrg.getString("pk") != null);
        if (!financeOrgValid) {
            errorMessages.append("财务结算组织不能为空！\n");
        }

        // 校验 details 部分
        for (int i = 0; i < details.size(); i++) {
            JSONObject detail = details.getJSONObject(i);
            String bstockclose = detail.getString("bstockclose");
            if ("Y".equalsIgnoreCase(bstockclose)) {
                continue; // 跳过 bstockclose 为 Y 的行
            }
            JSONObject pkMaterial = detail.getJSONObject("pk_material");
            HashMap<String, Object> addParams = null;
            if (pkMaterial != null && !pkMaterial.isEmpty()) {
                addParams = wareHouseInventoryMapper.selectAdditionalManagement(pkMaterial.getString("pk"));
            }

            assert pkMaterial != null;
            String materialName = pkMaterial.getString("name");
            StringBuilder materialErrors = new StringBuilder(materialName + "：");

            checkFieldNotNull(detail, "pk_material", "物料不能为空", materialErrors);
            checkFieldIsNumber(detail, "nnum", "实收主数量为空或输入内容非数字", materialErrors);

            checkFieldIsNumber(detail, "nastnum", "应收数量为空或输入内容非数字", materialErrors);
            checkFieldNotNull(detail, "pk_order_b", "主键不能为空", materialErrors);

            if (addParams != null && addParams.get("code") != null) {
                // 1表示仅库存状态，2表示仅生产厂商，3表示库存状态和生产厂商
                if ("1".equals(addParams.get("code")) || "3".equals(addParams.get("code"))) {
                    checkFieldNotNull(detail, "cstateid", "库存状态不能为空", materialErrors);
                }
            }

            if (addParams != null && addParams.get("wholemanaflag") != null && "Y".equals(addParams.get("wholemanaflag"))) {
//                checkFieldNotNull(detail, "vvendbatchcode", "供应商批号不能为空", materialErrors);
                checkFieldNotNull(detail, "vbatchcode", "批号不能为空", materialErrors);
            }

            checkFieldNotNull(detail, "crowno", "行号不能为空", materialErrors);
            if (addParams != null && addParams.get("qualitymanflag") != null && "Y".equals(addParams.get("qualitymanflag"))) {
                checkFieldNotNull(detail, "dproducedate", "生产日期不能为空", materialErrors);
                checkFieldNotNull(detail, "dvalidate", "有效期不能为空", materialErrors);
            }

            // 新增的校验：如果nnum为负数，检查 pk_batchcode 和 vbatchcode 是否为空
            if (detail.getDouble("nnum") < 0) {
                if (addParams != null && addParams.get("wholemanaflag") != null && "Y".equals(addParams.get("wholemanaflag"))) {
                    checkFieldNotNull(detail, "pk_batchcode", "批次编码不能为空", materialErrors);
                    checkFieldNotNull(detail, "vbatchcode", "批号不能为空", materialErrors);
//                    inventoryManagerUtils.isEnough("", vtrantypecode, pkMaterial, detail.getString("vbatchcode"), detail.getDouble("nnum"), "1", detail.getString("cstateid"));
                }
            }

            // 如果该物料有错误信息，添加到总错误信息中
            if (!materialErrors.toString().endsWith("：")) {
                // 去掉最后的 "、"，并追加到总错误信息中
                errorMessages.append(materialErrors, 0, materialErrors.length() - 1).append("\n");
            }
        }

        // 如果有错误，抛出异常或返回错误信息
        if (errorMessages.length() > 0) {
            throw new IllegalArgumentException("校验失败:\n" + errorMessages);
        }

        // 封装阶段，将所有 JSONObject 替换为 pk 值
        JSONObject newHeader = repackHeader(header);
        JSONArray newDetails = repackDetails(details);

        // 构建新 JSON 并返回
        JSONObject result = new JSONObject();
        result.put("header", newHeader);
        result.put("details", newDetails);
        return result;
    }

    /**
     * 处理PK值是否为空
     *
     * @param obj           JSONObject
     * @param field         字段名
     * @param errorMsg      错误信息
     * @param errorMessages 错误信息集合
     */
    private static void checkFieldNotNull(JSONObject obj, String field, String errorMsg, StringBuilder errorMessages) {
        if (obj.get(field) instanceof JSONObject) {
            JSONObject jsonField = obj.getJSONObject(field);
            if (jsonField == null || jsonField.getString("pk") == null) {
                errorMessages.append(errorMsg).append("、");
            }
        } else if (obj.getString(field) == null || obj.getString(field).isEmpty()) {
            errorMessages.append(errorMsg).append("、");
        }
    }

    /**
     * 处理PK值是否为空
     *
     * @param obj           JSONObject
     * @param field         字段名
     * @param errorMsg      错误信息
     * @param errorMessages 错误信息集合
     */
    private static void checkFieldIsNumber(JSONObject obj, String field, String errorMsg, StringBuilder errorMessages) {
        Object fieldValue = obj.get(field);

        if (fieldValue != null) {
            // 如果是数字类型，直接处理
            if (!(fieldValue instanceof Number)) {
                if (fieldValue instanceof String) {
                    // 如果是字符串，尝试转换为数字
                    try {
                        Double.parseDouble((String) fieldValue);
                    } catch (NumberFormatException e) {
                        errorMessages.append(errorMsg).append("、");
                    }
                } else {
                    errorMessages.append(errorMsg).append("、");
                }
            }
        }
    }

    /**
     * 提取Header中的pk值
     *
     * @param header 表头
     * @return 表头
     */
    private static JSONObject repackHeader(JSONObject header) {
        JSONObject newHeader = new JSONObject();
        for (String key : header.keySet()) {
            Object value = header.get(key);
            if (value instanceof JSONObject) {
                // 如果是 JSONObject，则取其 pk 值
                newHeader.put(key, ((JSONObject) value).getString("pk"));
            } else {
                // 直接复制其他字段
                newHeader.put(key, value);
            }
        }
        return newHeader;
    }

    /**
     * 提取Details中的pk值
     *
     * @param details 表体信息
     * @return 表体信息
     */
    private static JSONArray repackDetails(JSONArray details) {
        JSONArray newDetails = new JSONArray();
        for (int i = 0; i < details.size(); i++) {
            JSONObject detail = details.getJSONObject(i);
            JSONObject newDetail = new JSONObject();
            for (String key : detail.keySet()) {
                Object value = detail.get(key);
                if (value instanceof JSONObject) {
                    // 如果是 JSONObject，则取其 pk 值
                    newDetail.put(key, ((JSONObject) value).getString("pk"));
                } else {
                    // 直接复制其他字段
                    newDetail.put(key, value);
                }
            }
            newDetails.add(newDetail);
        }
        return newDetails;
    }


    /**
     * 组装创建采购入库单请求体
     *
     * @param inputObject 输入对象
     * @return JSON结果
     */
    private JSONObject assemblyRequest(JSONObject inputObject, String userName) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 获取 header 和 details
        JSONObject header = inputObject.getJSONObject("header");
        JSONArray details = inputObject.getJSONArray("details");

        // 构建结果
        JSONObject formattedObject = new JSONObject();
        JSONObject icPurchaseinH = new JSONObject();
        JSONArray icPurchaseinB = new JSONArray();

        // 构建 ic_purchasein_h
        icPurchaseinH.put("cpurorgoid", header.getString("cpurorgoid"));
        icPurchaseinH.put("pk_org", PK_ORG);
        icPurchaseinH.put("cwarehouseid", header.getString("cwarehouseid"));
        icPurchaseinH.put("cfanaceorgoid", PK_ORG);
        icPurchaseinH.put("creationtime", sdf.format(new Date()));
        icPurchaseinH.put("cbizid", header.getString("cemployeeid"));
        String piOrderNumber = documentNoUtils.generatePiOrderNumber();
        icPurchaseinH.put("vdef49", piOrderNumber);
        icPurchaseinH.put("vdef50", piOrderNumber);
        icPurchaseinH.put("cwhsmanagerid", userName);
//        icPurchaseinH.put("vdef18", "Y");

        // 构建 ic_purchasein_b
        for (Object detail : details) {
            JSONObject detailObj = (JSONObject) detail;
            JSONObject icPurchaseInBodyItem = new JSONObject();
            icPurchaseInBodyItem.put("cmaterialvid", detailObj.getString("pk_material"));
            if (detailObj.getDouble("nnum") < 0) {
                icPurchaseinH.put("freplenishflag", "Y");
                if (detailObj.getString("pk_batchcode") != null && !Objects.equals(detailObj.getString("pk_batchcode"), "N/A")) {
                    icPurchaseInBodyItem.put("pk_batchcode", detailObj.getString("pk_batchcode"));
                }
            }
//            JSONObject pkMaterial = detailObj.getJSONObject("pk_material");
//            HashMap<String, Object> addParams = null;
//            if (pkMaterial != null && !pkMaterial.isEmpty()) {
//                addParams = wareHouseInventoryMapper.selectAdditionalManagement(pkMaterial.getString("pk"));
//            }
            icPurchaseInBodyItem.put("nnum", detailObj.getString("nnum"));
            double quantity = calculateReceivableQuantity(detailObj.getString("nnum"), detailObj.getString("vchangerate"));
            icPurchaseInBodyItem.put("nassistnum", quantity);
            icPurchaseInBodyItem.put("nshouldassistnum", quantity);
            icPurchaseInBodyItem.put("nshouldnum", detailObj.getString("nnum"));
            icPurchaseInBodyItem.put("csourcebillbid", detailObj.getString("pk_order_b"));
            icPurchaseInBodyItem.put("csourcebillhid", header.getString("pk_order"));
            icPurchaseInBodyItem.put("vsourcebillcode", header.getString("vbillcode"));
            icPurchaseInBodyItem.put("vfirstbillcode", header.getString("vbillcode"));
            icPurchaseInBodyItem.put("cfirstbillhid", header.getString("pk_order"));
            icPurchaseInBodyItem.put("cfirstbillbid", detailObj.getString("pk_order_b"));
            icPurchaseInBodyItem.put("cstateid", detailObj.getString("cstateid"));
            icPurchaseInBodyItem.put("csourcetranstype", header.getString("ctrantypeid"));
            icPurchaseInBodyItem.put("vvendbatchcode", detailObj.getString("vvendbatchcode"));
            if (detailObj.getString("vbatchcode") != null && !Objects.equals(detailObj.getString("vbatchcode"), "N/A")) {
                icPurchaseInBodyItem.put("vbatchcode", detailObj.getString("vbatchcode"));
            }
            icPurchaseInBodyItem.put("vsourcerowno", detailObj.getString("crowno"));
            if (detailObj.getString("dproducedate") != null) {
                icPurchaseInBodyItem.put("dproducedate", sdf.format(detailObj.getDate("dproducedate")));
            }
            if (detailObj.getString("dvalidate") != null) {
                icPurchaseInBodyItem.put("dvalidate", sdf.format(detailObj.getDate("dvalidate")));
            }
            icPurchaseInBodyItem.put("csourcetype", header.getString("vtrantypecode"));
            icPurchaseInBodyItem.put("cfirsttype", header.getString("vtrantypecode"));
            icPurchaseInBodyItem.put("vfirstrowno", detailObj.getString("crowno"));
            if (detailObj.getString("vbdef48") != null && !detailObj.getString("vbdef48").isEmpty()) {
                icPurchaseInBodyItem.put("vbdef48", sdf.format(detailObj.getDate("vbdef48")));
            }
            icPurchaseInBodyItem.put("vbdef49", detailObj.getString("vbdef49"));
            icPurchaseInBodyItem.put("vbdef50", detailObj.getString("vbdef50"));
            icPurchaseInBodyItem.put("vbcdef2", detailObj.getString("vbcdef2"));
            icPurchaseInBodyItem.put("vbcdef3", detailObj.getString("vbcdef3"));

            icPurchaseinB.add(icPurchaseInBodyItem);
        }

        // 合并结果
        formattedObject.put("ic_purchasein_h", icPurchaseinH);
        formattedObject.put("ic_purchasein_b", icPurchaseinB);

        return formattedObject;
    }

    /**
     * 主辅数量换算
     *
     * @param number 主数量
     * @param unit   换算单位
     * @return 换算结果
     */
    private double calculateReceivableQuantity(String number, String unit) {
        if (number != null) {
            double parseDouble = Double.parseDouble(number);
            String[] proportion = unit.split("/");
            double numerator = Double.parseDouble(proportion[0]);
            double denominator = Double.parseDouble(proportion[1]);
            if (denominator == 0) {
                throw new ArithmeticException("换算系数的分母不能为零！");
            }
            double v = numerator / denominator;
            return parseDouble / v;
        } else {
            return 0;
        }
    }

    /**
     * 采购入库单撤回
     *
     * @param headerId  采购入库单表头主键
     * @param loginUser 登录用户
     * @return 撤回结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult orderBack(String headerId, LoginUser loginUser) {
        HashMap<String, String> billStatusMap = purchaseInStockMapper.getBillStatus(headerId);
        String billState = billStatusMap.get("billState");
        String vbillCode = billStatusMap.get("vbillcode");
        AjaxResult ajaxResult = messageUtil.cancelExtractBillMessage(billState, DocumentType.PURCHASE_INBOUND.getDescription());
        return ajaxResult.isSuccess() ? processOrderBack(headerId, loginUser, vbillCode) : ajaxResult;
    }

    private AjaxResult processOrderBack(String headerId, LoginUser loginUser, String vbillCode) {
        // 撤回采购入库单表头
        int i = purchaseInStockMapper.orderBackHead(headerId, loginUser.getUserId().toString());
        String vbillcode = purchaseInStockMapper.selectVbillcodeByHeaderId(headerId);
        if (i > 0) {
            // 撤回采购入库单表体
            int i1 = purchaseInStockMapper.orderBackDetails(headerId, loginUser.getUserId().toString());
            if (i1 > 0) {
                return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vbillcode), DocumentType.PURCHASE_INBOUND.getDescription(), "取消提取"));
            }
        }
        return AjaxResult.error("系统出现未知错误，请联系系统管理员处理！");
    }

    /**
     * 更新库存
     *
     * @param cgeneralhid 采购入库单表头主键
     * @param loginUser   操作用户
     * @return 更新结果
     */
    @Override
    public AjaxResult updateInventory(String cgeneralhid, LoginUser loginUser) {
        try {
            // 获取表头信息
            PurchaseInboundHeadVO purchaseInboundHeadVO = purchaseInStockMapper.selectPurchaseInHeaderByBillCode(cgeneralhid);

            // 获取明细信息
            List<PurchaseInboundBodyVO> details = purchaseInStockMapper.selectPurchaseInStockDetails(cgeneralhid, null);

            // 检查库存是否充足
            inventoryManagerUtils.verifyInventorySign(details, "warehousein", purchaseInboundHeadVO.getVtrantypecode(), DocumentType.PURCHASE_INBOUND.getDescription());

            // 执行入库操作
            Integer rowCount = inventoryManagerUtils.wmsWarehouseIn(purchaseInboundHeadVO.getVbillcode(), "PurchaseWareHouseIn");

            // 更新单据状态
            updateBillState(cgeneralhid, loginUser, rowCount, details.size());

            return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(purchaseInboundHeadVO.getVbillcode()), DocumentType.PURCHASE_INBOUND.getCode(), "签字"));
        } catch (InventoryException e) {
//            log.error("库存检查失败: {}", e.getMessage());
            return AjaxResult.error(e.getMessage());
        } catch (Exception e) {
//            log.error("更新库存失败: {}", e.getMessage());
            return AjaxResult.error(e.getMessage());
        }

    }

    /**
     * 检查库存是否充足
     *
     * @param details               明细信息
     * @param purchaseInboundHeadVO 表头信息
     * @throws InventoryException 库存异常
     */
    private void checkInventory(List<PurchaseInboundBodyVO> details, PurchaseInboundHeadVO purchaseInboundHeadVO) throws InventoryException {
        for (PurchaseInboundBodyVO detail : details) {
            if (detail.getNshouldnum() < 0) {
                int resultType = inventoryManagerUtils.isEnough(
                        detail.getVbillcode(),
                        purchaseInboundHeadVO.getVtrantypecode(),
                        detail.getCmaterialvid().getPk(),
                        detail.getVbatchcode(),
                        detail.getNnum(),
                        "2",
                        detail.getCstateid(), "", "");
                if (resultType == InventoryCheck.NO_ENOUGH.ordinal()) {
                    throw new InventoryException(detail.getCmaterialvid().getName() + "库存可用量不足！");
                } else if (resultType == InventoryCheck.NOT_ALLOWED.ordinal()) {
                    throw new InventoryException(detail.getCmaterialvid().getName() + "当前商品不支持在此单据类型下使用！");
                }
            }
        }
    }

    /**
     * 更新单据状态
     *
     * @param cgeneralhid 单据主键
     * @param loginUser   登录用户
     * @param rowCount    入库数量
     * @param detailSize  明细数量
     */
    private void updateBillState(String cgeneralhid, LoginUser loginUser, Integer rowCount, int detailSize) {
        if (rowCount != null && detailSize == rowCount) {
            purchaseInStockMapper.updateBillState(cgeneralhid, BillStatusConstant.SIGNED_CODE, loginUser.getUsername(), DataProcessUtils.getLocalDate());
        } else {
            throw new RuntimeException(messageUtil.updateDocumentWmsFailureMessage(DocumentType.PURCHASE_INBOUND.getCode()));
        }
    }
}
